import queue
import os
import socket
import threading
import time
import queue

### 返回当前系统运行时间，单位毫秒
def get_current_ms():
    return time.time_ns()/1000000

### 选择信息输出，console:终端输出，server：udp服务器输出
def DEBUG(str, console, server):
    if console:
        print(str)
    if server:
        add_data(bytes(str+'\n', "utf-8"))

udp_client_map = {} #{addr+port: (addr, time)}
udp_map_lock = threading.Lock()
udp_send_queue = queue.Queue(0)

def add_data(data):
    global udp_send_queue
    if len(udp_client_map)>0:
        udp_send_queue.put(data)

def clear_data():
    global udp_send_queue
    udp_send_queue.queue.clear()

### 监听按键，退出程序
def app_exit(udp):
    udp.close()
    print("Key: CTRL+X")
    os._exit(0)

### 检查udp客户端列表，存在超时就删除
def check_client_map(udp):
    global udp_client_map
    global udp_map_lock
    while True:
        if len(udp_client_map)>0:
            udp_map_lock.acquire()
            cmap = udp_client_map.copy()
            udp_map_lock.release()

            now = get_current_ms()
            for k,v in cmap.items():
                if now>v[1] and now-v[1]>20000:
                    udp_map_lock.acquire()
                    del udp_client_map[k]
                    udp_map_lock.release()

                    msg = "LOG-->UDP Client Send Timeout: remove (%s->%d)\n" % (k, len(udp_client_map))
                    DEBUG(msg, True, True)
        time.sleep(0.5)

### 更新udp客户端列表
def update_client(name, addr):
    global udp_map_lock
    udp_map_lock.acquire()
    udp_client_map[name] = (addr, get_current_ms())
    udp_map_lock.release()

### udp服务器向客户端分发数据
def udp_send_task(udp):
    while True:
        if len(udp_client_map)==0:
            clear_data()
        else:
            while not udp_send_queue.empty():
                data = udp_send_queue.get()

                if len(data)<=0:
                    continue

                udp_map_lock.acquire()
                cmap = udp_client_map.copy()
                udp_map_lock.release()
                
                for k,v in cmap.items():
                    udp.sendto(data, v[0])

        time.sleep(0.005)

### UDP服务器接收数据任务
def udp_rec_task(udp):
    while True:
        try:
            data, addr = udp.recvfrom(4096)
            if len(data)>0:
                #udp_send_queue.put(data)
                name = "%s->%d" % (addr[0], addr[1])
                if name not in udp_client_map:
                    msg = "LOG-->UDP Client Map: add (%s)\n" % name
                    DEBUG(msg, True, True)
                update_client(name, addr)

                msg = "LOG-->UDP Server Rec: (%s): %d\n" % (name, len(data))
                DEBUG(msg, False, True)
        except:
            DEBUG("LOG-->UDP Server Recvfrom Error!", True, True)

        time.sleep(0.005)

def udp_server_run(udp):
    td1 = threading.Thread(target=udp_send_task, args=(udp,))
    td1.start()

    td2 = threading.Thread(target=udp_rec_task, args=(udp,))
    td2.start()

def check_run(udp):
    td = threading.Thread(target=check_client_map, args=(udp,))
    td.start()

def log_udp_server_run(host, port):
    global udp_server
    host = host
    port = port
    udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_server.bind((host, port))

    check_run(udp_server)    #检查客户端列表，超时则删除
    udp_server_run(udp_server) #UDP服务器发送任务
    